package com.simen.hellobytes;

import com.simen.hellobytes.exception.CreateDirectoryException;
import com.simen.hellobytes.exception.DeleteDirectoryException;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * @author Created by Simen.
 * @date 创建日期 2018/5/26 11:02
 * @modify 修改者 Simen
 */
public class DirUtil {

    public static final int SORT_BY_NAME = 1;
    public static final int SORT_BY_CREATE_TIME = 2;
    public static final int SORT_BY_FILE_SIZE = 3;

    public static final int SORT_BY_NAME_REVERT = -1;
    public static final int SORT_BY_CREATE_TIME_REVERT = -2;
    public static final int SORT_BY_FILE_SIZE_REVERT = -3;

    public interface FileFilter {
        String filter(File file);
    }

    /**
     * 获取当前运行环境绝对路径
     *
     * @return
     */
    public static String getCurrentAbsolutePath() {
        String userDir = System.getProperty("user.dir");

        if (userDir == null) {
            return new File("").getAbsolutePath();
        } else {
            return new File(userDir).getAbsolutePath();
        }
    }

    public static boolean createDirWithResult(String dirPath){
        return createDirWithResult(new File(dirPath));
    }

    public static boolean createDirWithResult(File dir){
        try {
            createDir(dir);
            return true;
        } catch (CreateDirectoryException e) {
            return false;
        }
    }

    /**
     * 创建目录(支持连续目录路径创建)
     *
     * @param dirPath
     * @throws CreateDirectoryException
     */
    public static void createDir(String dirPath) throws CreateDirectoryException {
        createDir(new File(dirPath));
    }

    public static void createDir(File dir) throws CreateDirectoryException {
        if (!dir.exists() || !dir.isDirectory()) {
            if (!dir.mkdirs()) {
                throw new CreateDirectoryException("directory create fail." + dir.getPath());
            }
        }
    }

    /**
     * 递归方式移除文件目录
     *
     * @param file
     * @return
     */
    public static void deleteDir(File file) throws DeleteDirectoryException {
        if (file.isDirectory()) {
            File[] children = file.listFiles();

            for (int i = 0; children != null && i < children.length; i++) {
                deleteDir(children[i]);
            }
        }

        if (file.exists() && !file.delete()) {
            throw new DeleteDirectoryException("delete " + (file.isDirectory() ? "directory" : "file")
                    + " fail " + file.getAbsolutePath());
        }
    }

    /**
     * 罗列指定目录下的所有文件
     *
     * @param dir
     */
    public static void listInfo(File dir) {
        listInfo(dir, 0);
    }

    /**
     * 罗列指定目录下的所有文件
     * <p>
     * eg:
     * <p>
     * - - resources
     * - - java
     * - - - - com
     * - - - - - - - simen
     * - - - - - - - - - hellobytes
     * - - - - - - - - - - - - ByteUtil.java
     * - - - - - - - - - - - - HexUtil.java
     *
     * @param dir
     * @param deep 控制间隔符号
     */
    private static void listInfo(File dir, int deep) {
        File[] childs = dir.listFiles();

        char[] seps = new char[3 + ((deep % 2 == 0) ? deep + 1 : deep)];

        for (int i = 0; i < seps.length; i++) {
            seps[i] = (i % 2 == 0) ? '-' : ' ';
        }

        String append = new String(seps);

        for (int i = 0; childs != null && i < childs.length; i++) {
            if (childs[i].isDirectory()) {
                System.out.println(append + childs[i].getName());

                listInfo(childs[i], deep + 5);
            } else {
                System.out.println(append + childs[i].getName());
            }
        }
    }

    /**
     * 查找指定目录下所有文件和子文件
     *
     * @param dir
     * @param fileFilter
     * @return 返回参数起到辅助作用, 对于想要在遍历文件过程中不同情况下的终止起到作用
     */
    public static String findFile(File dir, FileFilter fileFilter) {
        File[] childFiles = dir.listFiles();

        if (childFiles != null) {
            for (int i = 0; i < childFiles.length; i++) {
                String message = fileFilter.filter(childFiles[i]);

                if (message != null) {
                    return message;
                }

                if (childFiles[i].isDirectory()) {
                    message = findFile(childFiles[i], fileFilter);

                    if (message != null) {
                        return message;
                    }
                }
            }
        }

        return null;
    }

    /**
     * 文件数组排序
     *
     * @param files
     * @param sortWay
     * @return
     */
    public static File[] fileSort(File[] files, int sortWay) {
        if (files == null || files.length == 0) {
            return files;
        }

        for (int i = 0; i < files.length - 1; i++) {
            for (int j = 0; j < files.length - 1 - i; j++) {
                if (compareFile(files[j], files[j + 1], sortWay)) {
                    File temp = files[j];
                    files[j] = files[j + 1];
                    files[j + 1] = temp;
                }
            }
        }

        return files;
    }

    private static boolean compareFile(File file1, File file2, int sortWay) {
        switch (sortWay) {
            default:
            case SORT_BY_NAME: {
                return file1.getName().compareToIgnoreCase(file2.getName()) >= 0;
            }
            case SORT_BY_NAME_REVERT: {
                return file1.getName().compareToIgnoreCase(file2.getName()) <= 0;
            }
            case SORT_BY_CREATE_TIME: {
                return file1.lastModified() >= file2.lastModified();
            }
            case SORT_BY_CREATE_TIME_REVERT: {
                return file1.lastModified() <= file2.lastModified();
            }
            case SORT_BY_FILE_SIZE: {
                return file1.length() >= file2.length();
            }
            case SORT_BY_FILE_SIZE_REVERT: {
                return file1.length() <= file2.length();
            }
        }
    }

    public static String getUniqueFileName(File dir, String defaultName) {
        File file = new File(dir, defaultName);
        String ext = null;
        String preName = null;

        int pointIndex = defaultName.lastIndexOf(".");
        if (pointIndex == -1) {
            ext = "";
            preName = defaultName;
        } else if (pointIndex == defaultName.length() - 1) {
            ext = "";
            preName = defaultName.substring(0, pointIndex);
        } else {
            ext = defaultName.substring(pointIndex + 1);
            preName = defaultName.substring(0, pointIndex);
        }

        int afterNum = 0;
        while (file.exists()) {
            afterNum++;
            file = new File(dir, preName + "(" + afterNum + ")." + ext);
        }

        return file.getName();
    }

    public static void copyDir(File fromDir, File toDir) throws IOException {
        if (!fromDir.exists() || !fromDir.isDirectory()) {
            throw new IOException("dir not exist " + fromDir.getPath());
        }

        File[] resources = fromDir.listFiles();
        DirUtil.createDir(toDir);

        for (int i = 0; resources != null && i < resources.length; i++) {
            if (resources[i].isDirectory()) {
                copyDir(resources[i], new File(toDir, resources[i].getName()));
            } else {
                File dstFile = new File(toDir, resources[i].getName());
                if (dstFile.exists()) {
                    throw new IOException(resources[i].getPath() + " already exist");
                }

                IOUtil.copyFile(resources[i], dstFile);
            }
        }
    }

    public static void copyFileFromDirToOtherDir(File file,File fromDir,File otherDir) throws IOException {
        copyFileFromDirToOtherDir(file,fromDir,otherDir,false);
    }

    public static void copyFileFromDirToOtherDir(File file,File fromDir,File otherDir,boolean move) throws IOException {
        if(!file.exists() || !file.isFile()){
            throw new FileNotFoundException(file.getPath());
        }

        String filePath=file.getPath();
        String fromDirPath=fromDir.getPath();

        if(!filePath.contains(fromDirPath)){
            throw new IOException("file:"+filePath+" is not in directory:"+fromDirPath);
        }

        DirUtil.createDir(otherDir);

        String otherDirPath=otherDir.getPath();
        String relativePath=filePath.replaceAll(fromDirPath,"");

        for (int i = 0; i < relativePath.length(); i++) {
            if(relativePath.charAt(i)!='/'
                    && relativePath.charAt(i)!='\\'){
                if(i>0) {
                    relativePath = relativePath.substring(i);
                }
                break;
            }
        }

        File dstFile=new File(otherDir,relativePath);
        File dstParentFile=dstFile.getParentFile();
        if(!otherDirPath.equals(dstParentFile.getPath())){
            DirUtil.createDir(dstParentFile);
        }

        if(move){
            if(!file.renameTo(dstFile)){
                throw new IOException("move file:"+file.getPath()+" fail");
            }
        }else {
            IOUtil.copyFile(file, dstFile);
        }
    }


}
